#include "Obj3d.h"

using namespace prog3d;
using namespace std;

/**
@author F. Aubert
*/


// Mapping de la structure de données stockée dans obj vers buffers OpenGL
void Obj3d::initBuffer() {
  // On commence par tout mettre dans des tableaux pour pouvoir les passer à OpenGL
  float *pts;
  pts=new float[_obj->nbVertex()*3]; // *3 car on mettra pour chaque sommet les 3 coordonnées x,y,z
  unsigned int *indice;
  indice=new unsigned int[_obj->nbFace()*3]; // *3 car on doit mettre les 3 indices constituant chacun des triangles.
  int i;
  float *normalPts;
  normalPts = new float[_obj->nbVertex()*3];

  for(i=0; i < _obj->nbVertex(); i++){
    pts[3*i+0] = _obj->point(i).x(); 
    pts[3*i+1] = _obj->point(i).y(); 
    pts[3*i+2] = _obj->point(i).z(); 
  }


  for(i=0; i < _obj->nbFace(); i++){
    indice[3*i+0] = _obj->face(i)->indice(0); 
    indice[3*i+1] = _obj->face(i)->indice(1); 
    indice[3*i+2] = _obj->face(i)->indice(2);  
  }
 
  for(i=0; i < _obj->nbVertex(); i++){
    normalPts[3*i+0] = _obj->normal(i).x(); 
    normalPts[3*i+1] = _obj->normal(i).y(); 
    normalPts[3*i+2] = _obj->normal(i).z();  
  }

  glGenBuffers(1,&_vertexBuffer);
  glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
  glBufferData(GL_ARRAY_BUFFER,_obj->nbVertex()*3*sizeof(float),pts,GL_STATIC_DRAW);

  glGenBuffers(1,&_indiceBuffer);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indiceBuffer);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER,_obj->nbFace()*3*sizeof(unsigned int),indice,GL_STATIC_DRAW);


  glGenBuffers(1,&_normalBuffer);
  glBindBuffer(GL_ARRAY_BUFFER, _normalBuffer);
  glBufferData(GL_ARRAY_BUFFER,_obj->nbVertex()*3*sizeof(float),normalPts,GL_STATIC_DRAW);

  // on supprime les tableaux de la mémoire centrale (tout est maintenant dans la mémoire OpenGL)
  delete[] pts;
  delete[] indice;
  delete[] normalPts;

}


// Tracé de l'objet
void Obj3d::drawBuffer() {
  
  // _obj->draw(); // Tracé face par face : à supprimer et à remplacer par le tracé des buffers initialisés dans initBuffer
  
  glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
  
  glEnableClientState(GL_VERTEX_ARRAY);
  glBindBuffer(GL_ARRAY_BUFFER,_vertexBuffer);
  glVertexPointer(3,GL_FLOAT,0,0);
  
  glEnableClientState(GL_NORMAL_ARRAY);
  glBindBuffer(GL_ARRAY_BUFFER, _normalBuffer);
  glNormalPointer(GL_FLOAT, 0, 0);
  
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,_indiceBuffer);
  glDrawElements(GL_TRIANGLES,3*_obj->nbFace(),GL_UNSIGNED_INT,0);
  
  glDisableClientState(GL_VERTEX_ARRAY);
  glDisableClientState(GL_NORMAL_ARRAY);
  


}

/** **************************************************************************************** */
/** **************************************************************************************** */
/** **************************************************************************************** */

Obj3d::Obj3d() {  //ctor
  _obj=NULL;
}

Obj3d::~Obj3d() { //dtor
  delete _obj;
}

void Obj3d::read(string nom) {
  _obj=new Soup();
  _obj->readOBJ(nom);
  _obj->triangulate();
  _obj->computeVertexNormal();
  _obj->setNumber();
  _obj->adaptBox(-2,2,-2,2,-2,2);
}

void Obj3d::draw() {
  _obj->draw();
}

void Obj3d::drawNormal() {
  _obj->drawNormal();
}
